using System;
using System.Timers;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Komires.MataliPhysics;
using WiimoteLib;

namespace MataliPhysicsDemo
{

    public class Camera2Animation1
    {
        // TEST VARIABLES
        static Timer _timer;
        static List<DateTime> _l; // Stores timer results
        public static List<DateTime> DateList;

        Matrix oldrotationX, oldrotationY;
        Matrix rotationX, rotationY;

        Vector3 deltaRotation;
        Vector3 olddeltaRotation;

        bool oldbuttonAstate = false;
        float oldAccel1 = 0;


        List<float> xaccis = new List<float>();
        List<float> yaccis = new List<float>();

        WiimoteCollection wc = new WiimoteCollection();

        // END TEST VARIABLES

        Demo demo;
        PhysicsScene scene;
        string instanceIndexName;

        string sphereName;
        string cursorName;
        string cursorAName;
        string cursorBName;
        string shotName;

        Shape sphere;
        PhysicsObject up;
        PhysicsObject body;
        PhysicsObject down;

        // Wiimote variables declaration
        Wiimote wm = new Wiimote();
        NunchukState oldNunchukState;
        WiimoteState oldWiiModeState;
        WiimoteState oldWiiModeState2;

        float positionX1 = 0;
        float oldpositionX1 = 0;
        float positionY1 = 0;
        float oldpositionY1 = 0;

        float accelX1 = 0;
        float accelY1 = 0;

        int ledWiimote = 1;

        private bool WiimoteEnable = true;  // Enable/Disable the wiimote control of the game

        // End wiimote variables declaration

        MouseState oldMouseState;
        KeyboardState oldKeyboardState;

        bool enableDistanceCollision;
        bool enableDistance;
        bool enableControl;
        float distance;

        float maxTangentLength;
        float maxDistance;

        Vector3 position;
        Vector3 direction;
        Matrix rotation;
        Matrix cameraRotation;
        Matrix oldcameraRotation;
        Matrix projection;
        Matrix view;

        Vector3 waterNormal;
        Vector3 moveForce;
        Viewport viewport;
        Vector2 mousePosition;
        Vector3 oldPosition;

        Vector3 vectorZero;
        Matrix matrixIdentity;
        Quaternion quaternionIdentity;

        public Camera2Animation1(Demo demo, int instanceIndex)
        {
            this.demo = demo;
            instanceIndexName = " " + instanceIndex.ToString();

            sphereName = "Sphere";
            cursorName = "Cursor";
            cursorAName = "Cursor A";
            cursorBName = "Cursor B";
            shotName = "Camera 2 Shot" + instanceIndexName + " ";

            maxTangentLength = 10.0f;
            maxDistance = -10.0f;

            vectorZero = Vector3.Zero;
            matrixIdentity = Matrix.Identity;
            quaternionIdentity = Quaternion.Identity;

            // Multiple Wiimote
            wc.FindAllWiimotes();

            foreach (Wiimote wm in wc)
            {
                wm.Connect();
                wm.SetReportType(InputReport.IRAccel, true);         
            }

            wc[0].SetLEDs(1);
            wc[1].SetLEDs(3);     
        }

        public void Initialize(PhysicsScene scene){
            this.scene = scene;
        }

        public void SetControllers(bool enableDistanceCollision){
            sphere = scene.Factory.ShapeManager.Find("Sphere");
            up = scene.Factory.PhysicsObjectManager.Find("Camera 2 Up" + instanceIndexName);
            body = scene.Factory.PhysicsObjectManager.Find("Camera 2 Body" + instanceIndexName);
            down = scene.Factory.PhysicsObjectManager.Find("Camera 2 Down" + instanceIndexName);

            oldMouseState = Mouse.GetState();
            oldKeyboardState = Keyboard.GetState();

            this.enableDistanceCollision = enableDistanceCollision;

            enableDistance = false;
            enableControl = false;

            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Find("Camera 2 Up" + instanceIndexName);

            if (objectBase != null)
            {
                objectBase.UserControllers.TransformMethods += new SimulateMethod(MoveCursor);
                objectBase.UserControllers.PostTransformMethods += new SimulateMethod(Move);
            }
        }

        public void RefreshControllers(){
            oldMouseState = Mouse.GetState();
            oldKeyboardState = Keyboard.GetState();
            oldWiiModeState = wc[0].WiimoteState;
            oldWiiModeState2 = wc[1].WiimoteState;
            oldNunchukState = wm.WiimoteState.NunchukState;
        }

        // Not important so far, should be used later to catch and throw balls maybe
        public void MoveCursor(SimulateMethodArgs args){
            PhysicsScene scene = demo.Engine.Factory.PhysicsSceneManager.Get(args.OwnerSceneIndex);
            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Get(args.OwnerIndex);

            if (!objectBase.Camera.Enabled) return;
            if (!objectBase.Camera.Active) return;

            float time = (float)args.Time;

            bool mouseButton = false;
            float mouseScrollWheel = 0.0f;

            MouseState mouseState = Mouse.GetState();

            mousePosition.X = mouseState.X;
            mousePosition.Y = mouseState.Y;
            mouseScrollWheel = mouseState.ScrollWheelValue;
            //mouseButton = mouseState.LeftButton == ButtonState.Pressed;

            bool hitMenu = false;
            if (demo.EnableMenu)
                hitMenu = (demo.MenuScene.MenuAnimation1.CurrentSwitch != null);

            objectBase.Camera.View.GetViewMatrix(ref view);
            objectBase.Camera.Projection.GetProjectionMatrix(ref projection);
            viewport = demo.GraphicsDevice.Viewport;

            CursorController cursorController = objectBase.InternalControllers.CursorController;
            cursorController.SetViewport(ref viewport);
            cursorController.SetViewMatrix(ref view);
            cursorController.SetProjectionMatrix(ref projection);
            cursorController.SetMousePosition(ref mousePosition);
            cursorController.MouseButton = mouseButton && !hitMenu;
            cursorController.MouseScrollWheel = mouseScrollWheel;
            cursorController.WindowActive = demo.IsActive;
            cursorController.Update();
        }

        // Main  method of the class
        // Controls the movement of the camera in the scene
        // So far the view is controlable with the wiimote : 
        //         - The view does not block when no IR sensors are found
        //         - The view continues to move on the previous direction when no ir sensors is found
        //         - It is still really buggy
        public void Move(SimulateMethodArgs args)
        {
            // Variables declaration ---------------------------------------------------------------*/

            PhysicsScene scene = demo.Engine.Factory.PhysicsSceneManager.Get(args.OwnerSceneIndex);
            PhysicsObject objectBase = scene.Factory.PhysicsObjectManager.Get(args.OwnerIndex);

            if (!objectBase.Camera.Enabled) return;
            if (!objectBase.Camera.Active) return;

            float time = (float)args.Time;

            //Vector3 deltaRotation = vectorZero;
            deltaRotation = vectorZero;

            Vector3 deltaTranslation = vectorZero;
            float rotationSpeed = 8.0f;
            float translationSpeed = 8.0f;
            float jumpSpeed = 0.5f;
            float translationInWaterFactor = 0.15f;
            bool enableJump = false;
            bool enableSwimUp = false;
            bool enableShot = false;

            bool BodyCollision = body.IsColliding();
            bool DownCollision = down.IsColliding();

            MouseState mouseState = Mouse.GetState();
            KeyboardState keyboardState = Keyboard.GetState();
            WiimoteState wiimoteState = wc[0].WiimoteState;
            WiimoteState wiimoteState2 = wc[1].WiimoteState;
            NunchukState nunchuckState = wm.WiimoteState.NunchukState;
            GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
            
            // END Variables declaration ---------------------------------------------------------------*/

            deltaRotation.Y += MathHelper.ToRadians(rotationSpeed * (mouseState.X - oldMouseState.X) * time);
            deltaRotation.X += MathHelper.ToRadians(rotationSpeed * (mouseState.Y - oldMouseState.Y) * time);

            mousePosition.X = mouseState.X;
            mousePosition.Y = mouseState.Y;
           
            if (WiimoteEnable)
            {
                // Save positions of X and Y for the view movement if IR 0 is found
                if (wiimoteState.IRState.IRSensors[0].Found)
                {
                    positionX1 = wiimoteState.IRState.IRSensors[0].RawPosition.X;
                    positionY1 = wiimoteState.IRState.IRSensors[0].RawPosition.Y;
                }
                else
                {
                    positionX1 = wiimoteState.IRState.IRSensors[0].RawPosition.X * 20/100;
                    positionY1 = wiimoteState.IRState.IRSensors[0].RawPosition.Y * 20/100;
                }

                // Save and control the jump ability of the character when the player shakes the wiimote 2
                accelX1 = wiimoteState2.AccelState.Values.X;
                accelY1 = wiimoteState2.AccelState.Values.Y;

                /*xaccis.Add(accelX1);
                yaccis.Add(accelY1);*/
                /*
                if (xaccis.Count == 1600)
                {
                    float averageX = 0;
                    float averageY = 0;

                    foreach (float xvalue in xaccis) // Loop through List with foreach
	                {
                        if (xvalue > averageX)
                            averageX = xvalue;

                        //averageX = xvalue + averageX;
	                }

                    foreach (float yvalue in yaccis) // Loop through List with foreach
                    {
                        if (yvalue > averageY)
                            averageY = yvalue;

                        //averageY = yvalue + averageY;
                    }

                   /* averageX = averageX / xaccis.Count;
                    averageY = averageY / xaccis.Count;

                    int caca = 0;
                }*/

                // Wiimote2 Button Movement
                if (wiimoteState.ButtonState.Left == true)
                    deltaTranslation.X -= translationSpeed * time / 8;

                if (wiimoteState.ButtonState.Right == true)
                    deltaTranslation.X += translationSpeed * time / 8;

                if (wiimoteState.ButtonState.Up == true)
                    deltaTranslation.Z += translationSpeed * time / 8;

                if (wiimoteState.ButtonState.Down == true)
                    deltaTranslation.Z -= translationSpeed * time / 8;

                //Reduce the rotation speed if the sensor is not found (stabilize the view of the player)
                if (oldWiiModeState.IRState.IRSensors[0].Found == false)
                    rotationSpeed = 0.1f;

                if (wiimoteState.ButtonState.A == true)
                {
                    // if the acceleration state is >=1, then jump
                    if (accelX1 >= 0.8)
                        enableJump = true;
                }

                // Jump condition
                if (wiimoteState2.ButtonState.A == true)
                {
                    deltaRotation.X = 0.3f;
                    deltaRotation.Y = 0.3f;
                    //position = oldPosition;

                    // Controls specifically the jump
                    /*if (wiimoteState2.ButtonState.A == true && wiimoteState2.ButtonState.B == false)
                    {
                    }*/

                    // Control the ball action if the two button are pressed at the same time
                    if (wiimoteState.ButtonState.A == true && wiimoteState.ButtonState.B == true)
                    {
                        deltaRotation.X = 0f;
                        deltaRotation.Y = 0f;
                        position = oldPosition;

                        if (accelX1 > 1.25 && accelY1 > 1.05)
                            enableShot = true;

                    } 
                }
                else
                {
                    // Check whether or not the Wiimote is found by IR Sensors
                    // Save the position to old position if it finds it
                    if (wiimoteState.IRState.IRSensors[0].Found)
                    {
                        oldPosition = position;
                        oldcameraRotation = cameraRotation;
                        oldrotationX = rotationX;
                        oldrotationY = rotationY;
                        olddeltaRotation = deltaRotation;
                    }

                    // Restore the good position if IR sensors are not found by the remote
                    if (wiimoteState.IRState.IRSensors[0].Found == false)
                    {
                        deltaRotation.X = olddeltaRotation.X * 0.4f;
                        deltaRotation.Y = olddeltaRotation.Y * 0.4f;
                        position = oldPosition;
                    }
                }
            }
            
            PhysicsObject cursorA = scene.Factory.PhysicsObjectManager.Find(cursorAName);
            PhysicsObject cursorB = scene.Factory.PhysicsObjectManager.Find(cursorBName);

            // Keyboard control
            if (!objectBase.Camera.EnableControl)
            {
                if (keyboardState.IsKeyDown(Keys.Z))
                    deltaTranslation.Z += translationSpeed * time / 5;

                if (keyboardState.IsKeyDown(Keys.S))
                    deltaTranslation.Z -= translationSpeed * time / 5;

                if (keyboardState.IsKeyDown(Keys.D))
                    deltaTranslation.X += translationSpeed * time / 5;

                if (keyboardState.IsKeyDown(Keys.Q))
                    deltaTranslation.X -= translationSpeed * time / 5;

                if (keyboardState.IsKeyDown(Keys.Space) && oldKeyboardState.IsKeyUp(Keys.Space))
                    enableJump = true;
            }

            // GamePad control
            if (!objectBase.Camera.EnableControl)
            {
                if (gamepadState.IsButtonDown(Buttons.LeftThumbstickUp))
                    deltaTranslation.Z += translationSpeed * time / 5;

                if (gamepadState.IsButtonDown(Buttons.LeftThumbstickDown))
                    deltaTranslation.Z -= translationSpeed * time / 5;

                if (gamepadState.IsButtonDown(Buttons.LeftThumbstickRight))
                    deltaTranslation.X += translationSpeed * time / 5;

                if (gamepadState.IsButtonDown(Buttons.LeftThumbstickLeft))
                    deltaTranslation.X -= translationSpeed * time / 5;
            }
           
            deltaRotation.X -= MathHelper.ToRadians(rotationSpeed * (oldpositionY1 - positionY1) * time / 3);
            deltaRotation.Y += MathHelper.ToRadians(rotationSpeed * (oldpositionX1 - positionX1) * time / 3);
                      
            // Save previous state of devices
            oldMouseState = mouseState;
            oldKeyboardState = keyboardState;
            oldWiiModeState = wiimoteState;

            // If enabled, it will save the old position of the wiimote considering different conditions
            if (WiimoteEnable)
            {
                // Save positions for the view movement if IR 0 is found
                if (wiimoteState.IRState.IRSensors[0].Found)
                {
                    oldpositionX1 = oldWiiModeState.IRState.IRSensors[0].RawPosition.X;
                    oldpositionY1 = oldWiiModeState.IRState.IRSensors[0].RawPosition.Y;
                }

                // Save positions for the view movement if IR 0 isn't found and IR 1 is found
                if (wiimoteState.IRState.IRSensors[0].Found == false && wiimoteState.IRState.IRSensors[1].Found)
                {
                    oldpositionX1 = oldWiiModeState.IRState.IRSensors[1].RawPosition.X;
                    oldpositionY1 = oldWiiModeState.IRState.IRSensors[1].RawPosition.Y;
                }

                if (wiimoteState.IRState.IRSensors[0].Found == false && wiimoteState.IRState.IRSensors[1].Found == false)
                {
                    oldpositionX1 = positionX1;
                    oldpositionY1 = positionY1;
                }
            }
            
            /* oldpositionX1 = oldWiiModeState.IRState.IRSensors[0].RawPosition.X;
             oldpositionY1 = oldWiiModeState.IRState.IRSensors[0].RawPosition.Y;*/

            Vector3 gravityDirection = vectorZero;
            scene.GetGravityDirection(ref gravityDirection);

            if (!objectBase.Camera.EnableControl)
            {
                // Rotation of the camera
                if (deltaRotation.LengthSquared() != 0.0f)
                {
                    Vector3 euler = vectorZero;
                    objectBase.Camera.GetEuler(ref euler);
                    Vector3.Add(ref euler, ref deltaRotation, out euler);
                    objectBase.Camera.SetEuler(ref euler);

                    Matrix rotationX, rotationY;
                    Matrix.CreateRotationX(-euler.X, out rotationX);
                    Matrix.CreateRotationY(-euler.Y, out rotationY);
                    Matrix.Multiply(ref rotationY, ref rotationX, out cameraRotation);

                    objectBase.Camera.SetRotation(ref cameraRotation);

                    Matrix.CreateRotationY(euler.Y, out rotation);

                    objectBase.RigidGroupOwner.MainWorldTransform.SetRotation(ref rotation);
                    objectBase.RigidGroupOwner.RecalculateMainTransform();
                }
            }
            else
            {
                Vector3 euler = vectorZero;
                Matrix objectRotation = matrixIdentity;
                objectBase.Camera.GetEuler(ref euler);
                Vector3.Add(ref euler, ref deltaRotation, out euler);
                objectBase.RigidGroupOwner.MainWorldTransform.GetRotation(ref objectRotation);

                //Matrix rotationX, rotationY;

                Matrix.CreateRotationX(euler.X, out rotationX);
                Matrix.CreateRotationY(euler.Y, out rotationY);

                Matrix.Multiply(ref rotationX, ref rotationY, out cameraRotation);
                Matrix.Multiply(ref cameraRotation, ref objectRotation, out rotation);

                objectBase.Camera.SetEuler(ref euler);
                objectBase.Camera.SetTransposeRotation(ref rotation);
            }

            if (deltaTranslation.LengthSquared() != 0.0f)
            {
                if (objectBase.RigidGroupOwner.IsUnderFluidSurface)
                {
                    objectBase.RigidGroupOwner.MaxPreIntegrationLinearVelocity = 10.0f;
                    objectBase.RigidGroupOwner.MaxPostIntegrationLinearVelocity = 10.0f;

                    if (enableSwimUp)
                    {
                        objectBase.InitLocalTransform.GetTransposeRotation(ref rotation);
                        Vector3.Transform(ref deltaTranslation, ref rotation, out direction);

                        objectBase.MainWorldTransform.GetRotation(ref rotation);
                        Vector3.Transform(ref direction, ref rotation, out moveForce);
                        Vector3.Multiply(ref moveForce, translationInWaterFactor * objectBase.RigidGroupOwner.Integral.Mass / (time * time), out moveForce);

                        objectBase.RigidGroupOwner.WorldAccumulator.AddWorldForce(ref moveForce);
                    }
                    else
                    {
                        objectBase.Camera.GetTransposeRotation(ref rotation);
                        Vector3.Transform(ref deltaTranslation, ref rotation, out moveForce);
                        Vector3.Multiply(ref moveForce, translationInWaterFactor * objectBase.RigidGroupOwner.Integral.Mass / (time * time), out moveForce);

                        objectBase.RigidGroupOwner.WorldAccumulator.AddWorldForce(ref moveForce);
                    }
                }
                else
                {
                    if (DownCollision)
                    {
                        objectBase.RigidGroupOwner.MaxPreIntegrationLinearVelocity = 100000.0f;
                        objectBase.RigidGroupOwner.MaxPostIntegrationLinearVelocity = 100000.0f;

                        objectBase.InitLocalTransform.GetTransposeRotation(ref rotation);
                        Vector3.Transform(ref deltaTranslation, ref rotation, out direction);

                        objectBase.MainWorldTransform.GetRotation(ref rotation);
                        Vector3.Transform(ref direction, ref rotation, out moveForce);
                        Vector3.Multiply(ref moveForce, objectBase.RigidGroupOwner.Integral.Mass / (time * time), out moveForce);

                        objectBase.RigidGroupOwner.WorldAccumulator.AddWorldForce(ref moveForce);
                        down.UpdateFeedbackForce(ref moveForce);
                    }
                    else
                    {
                        if (objectBase.RigidGroupOwner.IsInFluid)
                        {
                            objectBase.RigidGroupOwner.MaxPreIntegrationLinearVelocity = 10.0f;
                            objectBase.RigidGroupOwner.MaxPostIntegrationLinearVelocity = 10.0f;

                            objectBase.InitLocalTransform.GetTransposeRotation(ref rotation);
                            Vector3.Transform(ref deltaTranslation, ref rotation, out direction);

                            objectBase.MainWorldTransform.GetRotation(ref rotation);
                            Vector3.Transform(ref direction, ref rotation, out moveForce);
                            Vector3.Multiply(ref moveForce, translationInWaterFactor * objectBase.RigidGroupOwner.Integral.Mass / (time * time), out moveForce);

                            objectBase.RigidGroupOwner.WorldAccumulator.AddWorldForce(ref moveForce);
                        }
                    }
                }
            }

            // JUMP ------------------------------------------------------------------
            //
            if (enableJump)
            {
                if (!enableControl && !objectBase.Camera.EnableControl && DownCollision && !down.IsUnderFluidSurface && !body.IsUnderFluidSurface)
                {
                    objectBase.RigidGroupOwner.MaxPreIntegrationLinearVelocity = 100000.0f;
                    objectBase.RigidGroupOwner.MaxPostIntegrationLinearVelocity = 100000.0f;

                    Vector3.Multiply(ref gravityDirection, -jumpSpeed * objectBase.RigidGroupOwner.Integral.Mass / (time * time), out moveForce);

                    objectBase.RigidGroupOwner.WorldAccumulator.AddWorldForce(ref moveForce);
                    down.UpdateFeedbackForce(ref moveForce);
                }
            }

            enableControl = objectBase.Camera.EnableControl;

            float gravityDistance = 0.0f;
            Vector3 gravityLinearVelocity = vectorZero;
            Vector3 tangentLinearVelocity = vectorZero;
            Vector3 velocity = vectorZero;

            objectBase.MainWorldTransform.GetLinearVelocity(ref velocity);
            Vector3.Dot(ref gravityDirection, ref velocity, out gravityDistance);
            Vector3.Multiply(ref gravityDirection, gravityDistance, out gravityLinearVelocity);
            Vector3.Subtract(ref velocity, ref gravityLinearVelocity, out tangentLinearVelocity);

            float tangentLength = tangentLinearVelocity.Length();

            if (tangentLength > maxTangentLength)
                tangentLinearVelocity *= maxTangentLength / tangentLength;

            Vector3.Add(ref gravityLinearVelocity, ref tangentLinearVelocity, out velocity);

            objectBase.RigidGroupOwner.MainWorldTransform.SetLinearVelocity(ref velocity);

            objectBase.Camera.Projection.CreatePerspectiveLH(1.0f, 10000.0f, 70.0f, demo.Window.ClientBounds.Width, demo.Window.ClientBounds.Height);

            objectBase.MainWorldTransform.GetPosition(ref position);
            objectBase.Camera.GetTransposeRotation(ref cameraRotation);

            objectBase.Camera.View.CreateLookAtLH(ref position, ref cameraRotation, distance);
            objectBase.Camera.UpdateFrustum();

            objectBase.Camera.View.GetViewMatrix(ref view);
            objectBase.Camera.Projection.GetProjectionMatrix(ref projection);
            viewport = demo.GraphicsDevice.Viewport;

            Vector3 rayPosition, rayDirection;

            rayPosition = rayDirection = vectorZero;

            objectBase.UnProjectToRay(ref mousePosition, ref viewport, ref view, ref matrixIdentity, ref projection, ref rayPosition, ref rayDirection);

            PhysicsObject cursor = scene.Factory.PhysicsObjectManager.Find(cursorName);

            if (cursor != null)
            {
                Vector3 cursorPosition = vectorZero;
                Matrix cursorLocalRotation = matrixIdentity;
                Matrix cursorWorldRotation = matrixIdentity;

                cursor.InitLocalTransform.GetPosition(ref cursorPosition);
                cursor.InitLocalTransform.GetRotation(ref cursorLocalRotation);
                cursor.MainWorldTransform.GetRotation(ref cursorWorldRotation);

                objectBase.Camera.GetTransposeRotation(ref cameraRotation);
                Matrix.Multiply(ref cursorLocalRotation, ref cameraRotation, out rotation);

                Vector3.Transform(ref cursorPosition, ref cursorWorldRotation, out position);

                cursor.MainWorldTransform.SetRotation(ref rotation);
                Vector3.Add(ref position, ref rayPosition, out position);
                Vector3.Add(ref position, ref rayDirection, out position);
                cursor.MainWorldTransform.SetPosition(ref position);

                cursor.RecalculateMainTransform();
            }

            CursorController cursorController = objectBase.InternalControllers.CursorController;

            if (cursorController.IsDragging)
            {
                if ((cursorController.HitPhysicsObject.InternalControllers.HeightmapController != null) && cursorController.HitPhysicsObject.InternalControllers.HeightmapController.Enabled)
                {
                    Vector3 cursorStartPosition = vectorZero;
                    Vector3 cursorEndPosition = vectorZero;

                    cursorController.GetAnchor1(ref cursorStartPosition);
                    cursorController.GetAnchor2(ref cursorEndPosition);

                    Vector3.Subtract(ref cursorEndPosition, ref cursorStartPosition, out direction);

                    float dir = direction.Y;

                    if (dir != 0.0f)
                    {
                        Vector3 scale = vectorZero;

                        cursorController.HitPhysicsObject.MainWorldTransform.GetScale(ref scale);

                        float positionX = cursorStartPosition.X + 0.5f * scale.X;
                        float positionY = cursorStartPosition.Y + 0.5f * scale.Y;
                        float positionZ = cursorStartPosition.Z + 0.5f * scale.Z;

                        // To move the heightmap surface by the cursor, add the following lines of code
                        // and remove the lines cursorStartPosition.Y += dir; and cursorController.SetAnchor1(ref cursorStartPosition);

                        //cursorController.HitPhysicsObject.MainWorldTransform.GetPosition(ref cursorStartPosition);

                        //Vector3.Add(ref cursorStartPosition, ref direction, out cursorStartPosition);

                        //cursorController.HitPhysicsObject.MainWorldTransform.SetPosition(ref cursorStartPosition);
                        //cursorController.HitPhysicsObject.RecalculateMainTransform();

                        // To change the friction and restitution of the heightmap surface by the cursor, add the following lines of code

                        //cursorController.HitPhysicsObject.InternalControllers.HeightmapController.SetFriction(positionX, positionY, positionZ, 0.0f);
                        //cursorController.HitPhysicsObject.InternalControllers.HeightmapController.SetRestitution(positionX, positionY, positionZ, 2.0f);

                        cursorController.HitPhysicsObject.InternalControllers.HeightmapController.AddHeight(positionX, positionY, positionZ, dir / scale.Y);
                        cursorController.HitPhysicsObject.InternalControllers.HeightmapController.UpdateBounding();

                        cursorStartPosition.Y += dir;
                        cursorController.SetAnchor1(ref cursorStartPosition);
                    }
                }

                if ((cursorController.HitPhysicsObject.InternalControllers.FluidController != null) && cursorController.HitPhysicsObject.InternalControllers.FluidController.Enabled)
                {
                    Vector3 cursorStartPosition = vectorZero;
                    Vector3 cursorEndPosition = vectorZero;

                    cursorController.GetAnchor1(ref cursorStartPosition);
                    cursorController.GetAnchor2(ref cursorEndPosition);

                    Vector3.Subtract(ref cursorEndPosition, ref cursorStartPosition, out direction);

                    if (direction.LengthSquared() != 0.0f)
                    {
                        // To move the water surface by the cursor, add the following lines of code
                        // and set EnableCursorInteraction flag to true in the Water class

                        //cursorController.HitPhysicsObject.MainWorldTransform.GetPosition(ref cursorStartPosition);

                        //Vector3.Add(ref cursorStartPosition, ref direction, out cursorStartPosition);

                        //cursorController.HitPhysicsObject.MainWorldTransform.SetPosition(ref cursorStartPosition);
                        //cursorController.HitPhysicsObject.RecalculateMainTransform();
                    }
                }
            }

            // SHOT --------------------------------------------------------------------------
            //
            if (enableShot)
            {
                PhysicsObject shot = scene.Factory.PhysicsObjectManager.Create(shotName + scene.SimulationFrameCount.ToString());

                shot.Shape = sphere;
                shot.UserTagStr = sphereName;

                Vector3 shotScale = vectorZero;
                shotScale.X = shotScale.Y = shotScale.Z = 6f;

                // Speed at which the object is thrown in the air - To modify later for realistic physic
                Vector3.Multiply(ref rayDirection, 0.02f, out rayDirection);

                shot.InitLocalTransform.SetRotation(ref matrixIdentity);
                shot.InitLocalTransform.SetPosition(ref rayPosition);
                shot.InitLocalTransform.SetScale(ref shotScale);

                shot.InitLocalTransform.SetLinearVelocity(ref rayDirection);
                shot.InitLocalTransform.SetAngularVelocity(ref vectorZero);
                shot.Integral.SetDensity(10.0f);
                shot.InitLocalTransform.SetScale(1.5f);
                shot.Material.Restitution = 0.75f;
                shot.Material.UserTagStr = "Basket";
                shot.MaxSimulationFrameCount = 100;
                shot.EnableCollisions = true;

                if ((up != null) && (body != null) && (down != null))
                {
                    shot.DisableCollision(up, true);
                    shot.DisableCollision(body, true);
                    shot.DisableCollision(down, true);
                    shot.MaxDisableCollisionFrameCount = 100;
                }

                if (shot.IsStatic)
                    scene.UpdateFromInitLocalTransform(shot);

            }

            objectBase.Camera.UpdatePhysicsObjects(true, true);
            objectBase.Camera.SortDrawPhysicsObjects(PhysicsCameraSortOrderType.DrawPriorityShapePrimitiveType);
            objectBase.Camera.SortTransparentPhysicsObjects(PhysicsCameraSortOrderType.DrawPriorityShapePrimitiveType);
        }

        static void Start()
        {
            _l = new List<DateTime>(); // Allocate the list
            _timer = new Timer(3000); // Set up the timer for 3 seconds
            //
            // Type "_timer.Elapsed += " and press tab twice.
            //
            _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
            _timer.Enabled = true; // Enable it
        }

        static void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _l.Add(DateTime.Now); // Add date on each timer event
        }
    }
}
